package com.mt.roll.core.utils;

import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * id生成器，使用redis自增接口实现
 * TODO 待完善
 *
 * @author jiff
 * @date 2018-12-1
 * @since 1.0
 */
@Component
public class IDGenerator {
    private RedisTemplate redisTemplate;
    private static IDGenerator idGenerator;

    /**
     * 4位年格式
     */
    public static final String PATTERN_YYYY = "yyyy";
    /**
     * 6位年月格式
     */
    public static final String PATTERN_YYYYMM = "yyyyMM";
    /**
     * 8位年月日格式
     */
    public static final String PATTERN_YYYYMMDD = "yyyyMMdd";
    /**
     * 10位年月日时格式
     */
    public static final String PATTERN_YYYYMMDDHH = "yyyyMMddHH";
    /**
     * 12位年月日时分格式
     */
    public static final String PATTERN_YYYYMMDDHHMM = "yyyyMMddHHmm";


    /**
     * 最大序列号长度
     */
    private static final int MAX_SEQUENCE_LENGTH = 20;
    /**
     * 最大随机数长度
     */
    private static final int MAX_RANDOM_LENGTH = 10;
    /**
     * 序列命名空间
     */
    private static final String KEY_PREFIX_SEQUENCE = "SEQUENCE_";
    private static final Map<String, SimpleDateFormat> commonDateFormats = new HashMap<>();
    private static final List<DecimalFormat> sequenceFormats = new ArrayList<>();

    static {
        commonDateFormats.put(PATTERN_YYYY, new SimpleDateFormat(PATTERN_YYYY));
        commonDateFormats.put(PATTERN_YYYYMM, new SimpleDateFormat(
                PATTERN_YYYYMM));
        commonDateFormats.put(PATTERN_YYYYMMDD, new SimpleDateFormat(
                PATTERN_YYYYMMDD));
        commonDateFormats.put(PATTERN_YYYYMMDDHH, new SimpleDateFormat(
                PATTERN_YYYYMMDDHH));
        commonDateFormats.put(PATTERN_YYYYMMDDHHMM, new SimpleDateFormat(
                PATTERN_YYYYMMDDHHMM));
        StringBuilder sequencePattern = new StringBuilder(MAX_SEQUENCE_LENGTH);
        for (int i = 0; i < MAX_SEQUENCE_LENGTH; i++) {
            sequencePattern.append("0");
            sequenceFormats.add(new DecimalFormat(sequencePattern.toString()));
        }
    }

    @Autowired(required = false)
    public void setRedisTemplate(RedisTemplate redisTemplate) {
        RedisSerializer stringSerializer = new StringRedisSerializer();
        //设置序列化Key的实例化对象
        redisTemplate.setKeySerializer(stringSerializer);
        //设置序列化Value的实例化对象
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        redisTemplate.setHashKeySerializer(stringSerializer);
        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        redisTemplate.setStringSerializer(stringSerializer);
        redisTemplate.afterPropertiesSet();
        this.redisTemplate = redisTemplate;
    }

    @PostConstruct
    private void init() {
        idGenerator = this;
        idGenerator.redisTemplate = this.redisTemplate;
    }

    /**
     * 生成主键
     *
     * @param sequenceName 序列名
     * @return 主键
     */
    public static long gen(String sequenceName) {
        return idGenerator.redisTemplate.opsForValue().increment(
                KEY_PREFIX_SEQUENCE + sequenceName, 1);
    }

    /**
     * 生成主键
     *
     * @param prefix         前缀，为空或null时则不使用前缀
     * @param pattern        时间戳格式，为空或null时不使用时间戳，已定义5种格式：{@link #PATTERN_YYYY}、{@link #PATTERN_YYYYMM}、{@link #PATTERN_YYYYMMDD}、{@link #PATTERN_YYYYMMDDHH}、{@link #PATTERN_YYYYMMDDHHMM}、
     * @param sequenceLength 序列长度，大于0时有效，否则使用序列原始值，最多{@value #MAX_SEQUENCE_LENGTH}位，超过{@value #MAX_SEQUENCE_LENGTH}默认为{@value #MAX_SEQUENCE_LENGTH}位
     * @param sequenceName   序列名，为空或null时则不生成序列值
     * @return prefix+timestamp+sequence
     */
    public static String gen(String prefix, String pattern, int sequenceLength,
                             String sequenceName) {
        return gen(prefix, pattern, sequenceLength, sequenceName, 0);
    }

    /**
     * 生成主键
     *
     * @param prefix         前缀，为空或null时则不使用前缀
     * @param pattern        时间戳格式，为空或null时不使用时间戳，已定义5种格式：{@link #PATTERN_YYYY}、{@link #PATTERN_YYYYMM}、{@link #PATTERN_YYYYMMDD}、{@link #PATTERN_YYYYMMDDHH}、{@link #PATTERN_YYYYMMDDHHMM}、
     * @param sequenceLength 序列长度，大于0时有效，否则使用序列原始值，最多{@value #MAX_SEQUENCE_LENGTH}位，超过{@value #MAX_SEQUENCE_LENGTH}默认为{@value #MAX_SEQUENCE_LENGTH}位
     * @param sequenceName   序列名，为空或null时则不生成序列值
     * @param randomLength   随机数长度，大于0时有效，最多{@value #MAX_RANDOM_LENGTH}位，超过{@value #MAX_RANDOM_LENGTH}默认为{@value #MAX_RANDOM_LENGTH}位
     * @return prefix+timestamp+sequence+random
     */
    public static String gen(String prefix, String pattern, int sequenceLength,
                             String sequenceName, int randomLength) {
        StringBuilder ids = new StringBuilder();
        if (!isEmpty(prefix)) {
            ids.append(prefix);
        }
        String timestamp = null;
        if (!isEmpty(pattern)) {
            timestamp = getFormattedDate(pattern);
        }
        if (timestamp != null) {
            ids.append(timestamp);
        }
        if (!isEmpty(sequenceName)) {
            long sequence = gen(sequenceName);
            if (sequenceLength > 0) {
                if (sequenceLength > MAX_SEQUENCE_LENGTH) {
                    sequenceLength = MAX_SEQUENCE_LENGTH;
                }
                String formatSequence = sequenceFormats.get(sequenceLength - 1)
                        .format(sequence);
                if (formatSequence.length() > sequenceLength) {
                    formatSequence = formatSequence.substring(formatSequence
                            .length() - sequenceLength);
                }
                ids.append(formatSequence);
            } else {
                ids.append(sequence);
            }
        }
        //随机数长度大于0时添加随机数
        if (randomLength > 0) {
            String random = RandomStringUtils.randomNumeric(randomLength);
            ids.append(random);
        }
        return ids.toString();
    }

    private static String getFormattedDate(String pattern) {
        SimpleDateFormat sdf = commonDateFormats.get(pattern);
        if (sdf == null) {
            try {
                sdf = new SimpleDateFormat(pattern);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if (sdf == null) {
            return null;
        }
        java.util.Date now = new java.util.Date();
        return sdf.format(now);
    }

    private static boolean isEmpty(String str) {
        if (str == null || str.trim().isEmpty()) {
            return true;
        }
        return false;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            System.out.println(RandomStringUtils.randomNumeric(1));
            System.out.println(RandomStringUtils.randomNumeric(2));
            System.out.println(RandomStringUtils.randomNumeric(4));
        }
        System.out.println(new DecimalFormat("00").format(103));
        System.out.println(new DecimalFormat("000").format(13));

    }

}
